﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using RonaldCamcam.XBeeFramework.Utilility;
using RonaldCamcam.XBeeApiFramework.Utilility;

namespace RonaldCamcam.XBeeFramework.Api
{    
    public class ApiRemoteCommand : ApiBase
    {
        public delegate void DataReceived(ApiRemoteCommand ac);
        public event DataReceived DataReceivedCompleted;

        public string PortStatus { get; set; }
        public Request CommandRequest { get; set; }
        public Response CommandResponse { get; set; }
        public List<byte> ReceivedData { get; set; }                       

        private SerialPort _port;
        private int _currentWaitTime;
        private byte[] _address;

        public Encoding Encoding
        {
            get
            {
                return _port.Encoding;
            }
        }

        public ApiRemoteCommand(XBee xbee, byte[] address)
        {
            _address = address;
            //initialize port
            _port = new SerialPort(xbee.ComPort, xbee.PortBaudRate, xbee.PortParity, xbee.PortDataBits, xbee.PortStopBits);
            _port.NewLine = Environment.NewLine;
            _port.WriteTimeout = (xbee.WriteTimeout != 0) ? xbee.WriteTimeout : 500; //set a default of 500 milliseconds if not specified
            _port.ReadTimeout = (xbee.ReadTimeOut != 0) ? xbee.ReadTimeOut : 500; //set a default of 500 milliseconds if not specified
            _port.DataReceived += new SerialDataReceivedEventHandler(_port_DataReceived);            
            _port.Open();            

            initCommand();
        }

        private void initCommand()
        {
            PortStatus = string.Empty;
            ReceivedData = new List<byte>();
            _currentWaitTime = XBee.WAIT_AFTER_WRITE_TIME;
        }

        public void Close()
        {
            _port.Dispose();
            _port.Close();
        }

        void _port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {            
            _port = sender as SerialPort;

            if (_port.IsOpen && e.EventType == SerialData.Chars)
            {
                byte[] data = new byte[_port.BytesToRead];
                //Copy data from buffer
                _port.Read(data, 0, _port.BytesToRead);

                foreach (byte b in data)
                    ReceivedData.Add(b);

                while (ResponseFactory.VerifyRemoteCheckSum(ReceivedData.ToArray()) == true)
                {
                    DataReceivedCompleted(this);
                }
                //else if (_port.ReadTimeout < _currentWaitTime)
                //{
                //    PortStatus = "Read timeout";
                //    DataReceivedCompleted(this);
                //}                
            }
            else
            {
                PortStatus = "Port is Closed";
                DataReceivedCompleted(this);
            }
        }

        internal void SendToXBee(byte[] parameter, ApplyRemoteChanges applyRemoteChanges)
        {
            if (DataReceivedCompleted != null)
            {
                //always initialize on new command
                initCommand();
                //build command frame
                byte[] frameCommand = FrameFactory.BuildRemoteCommand(_address, parameter, ApiIdentifier, applyRemoteChanges, _port.Encoding);                
                //send it through the serial port
                _port.Write(frameCommand, 0, frameCommand.Length);
                //needed wait time
                Thread.Sleep(XBee.WAIT_AFTER_WRITE_TIME);                
            }
        }        
    }
}
